<?php

namespace App\Services\Sales;
use App\Common\BnFormatConfig;
use App\Common\Tools;
use App\Exceptions\BusinessException;
use App\Common\Constant;
use App\Common\ResponseCode;
use App\Params\Backend\DeliveryCompanyListParams;
use App\Params\Backend\DeliveryListParams;
use App\Params\Backend\DeliveryUpdateParam;
use App\Repository\DeliveryRepository;
use App\Repository\OrderItemRepository;
use App\Repository\OrderRepository;
use App\Services\BaseService;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;

/**
 * 物流发货相关业务类
 *
 * @author WangBin
 * @date 2021-09-24
 * @package App\Http\Services\Sales
 */
class DeliveryService extends BaseService
{
    /**
     * 获取发货单初始化数据
     *
     * @return array
     */
    public function getInit()
    {
        return [
            'company_list' => DeliveryRepository::getInstance()->getCompanyList()->get()
        ];
    }

    /**
     * 获取物流公司列表
     *
     * @param DeliveryCompanyListParams $params
     * @return array
     */
    public function getCompanyList(DeliveryCompanyListParams $params)
    {
        $company = DeliveryRepository::getInstance()->getCompanyList($params->toArray());
        return $this->toList($company, $params->getPage(), $params->getPageSize());
    }

    /**
     * 保存发货单
     *
     * @param DeliveryUpdateParam $param
     * @return array
     * @throws BusinessException
     */
    public function update(DeliveryUpdateParam $param)
    {
        // 校验订单
        $order = OrderRepository::getInstance()->getById($param->getOrderId());
        if(!in_array($order->status, Constant::ORDER_STATUS_CAN_DELIVERY) || $order->is_delivery == 1) {
            throw new BusinessException(ResponseCode::DELIVERY_ORDER_STATUS_ERROR);
        }
        // 校验物流单号唯一
        $checkExpressBn = DeliveryRepository::getInstance()->checkExpressBnUnique($param->getExpressBn(), $param->getDeliveryId());
        if($checkExpressBn) {
            throw new BusinessException(ResponseCode::DELIVERY_EXPRESS_BN_EXIST);
        }
        // 校验物流公司
        $company = DeliveryRepository::getInstance()->getCompany($param->getCompanyId());
        if(is_null($company)) {
            throw new BusinessException(ResponseCode::DELIVERY_COMPANY_NOT_EXIST);
        }

        try {
            DB::beginTransaction();
            $data = [
                'store_id' => $param->getStoreId(),
                'delivery_bn' => Tools::buildBn(BnFormatConfig::DELIVERY_BN_KEY),
                'order_id' => $param->getOrderId(),
                'order_bn' => $order->order_bn,
                'total_amount' => $order->pay_amount,
                'qty_ordered' => $order->qty_ordered,
                'total_qty' => $order->qty_ordered,
                'customer_id' => $order->customer_id,
                'customer_name' => $order->customer_name,
                'express_bn' => $param->getExpressBn(),
                'company_bn' => $company->company_bn,
                'company_name' => $company->name,
                'express_amount' => $order->express_amount,
                'consignee' => $order->consignee,
                'mobile' => $order->mobile,
                'full_address' => $order->address,
                'remark' => $param->getRemark(),
            ];

            // 保存发货单
            $delivery = DeliveryRepository::getInstance()->update($data, $param->getDeliveryId());

            // 获取订单明细
            $orderItems = OrderRepository::getInstance()->getItems($param->getOrderId());
            $items = collect($orderItems)->map(function ($orderItem) use ($delivery) {
                return [
                    'delivery_id' => $delivery->delivery_id,
                    'goods_id' => $orderItem->goods_id,
                    'goods_bn' => $orderItem->goods_bn,
                    'product_id' => $orderItem->product_id,
                    'name' => $orderItem->name,
                    'unit' => $orderItem->unit,
                    'price' => $orderItem->price,
                    'specs' => $orderItem->specs,
                    'weight' => $orderItem->weight,
                    'delivery_qty' => $orderItem->qty_ordered,
                    'qty_ordered' => $orderItem->qty_ordered,
                    'total_amount' => $orderItem->total_amount,
                    'delivery_amount' => $orderItem->total_amount,
                ];
            })->toArray();
            // 保存发货单明细
            $deliveryItem = DeliveryRepository::getInstance()->updateItems($items, $delivery->delivery_id);
            if(!$deliveryItem) {
                throw new BusinessException(ResponseCode::DELIVERY_CREATE_FAIL);
            }

            // 回写订单发货数据
            $orderData = [
                'delivery_qty' => $data['total_qty'],
                'delivery_amount' => $data['total_amount'],
                'delivery_at' => $delivery->created_at,
                'is_delivery' => 1,
                'status' => Constant::ORDER_STATUS_DELIVERY_ALL
            ];
            OrderRepository::getInstance()->update($orderData, $param->getOrderId());

            // 回写订单明细发货数据
            foreach ($items as $item) {
                $orderItem = OrderItemRepository::getInstance()->getByOrderAndProduct($param->getOrderId(), $item['product_id']);
                if(is_null($orderItem)) {
                    throw new \Exception('查询订单明细出错');
                }
                $orderItemData = ['delivery_qty' => $item['delivery_qty'], 'is_delivery' => 1, 'delivery_amount' => $item['total_amount']];
                OrderItemRepository::getInstance()->update($orderItemData, $orderItem->item_id);
            }
            DB::commit();
            return $delivery->delivery_id;
        } catch (\Exception $exception) {
            DB::rollBack();
            Log::error("[发货单] 失败：{$exception->getMessage()}");
            throw new BusinessException(ResponseCode::DELIVERY_CREATE_FAIL);
        }
    }

    /**
     * 发货单列表
     *
     * @param DeliveryListParams $params
     * @return array
     */
    public function getList(DeliveryListParams $params)
    {
        $deliveryList = DeliveryRepository::getInstance()->getList($params->toArray());
        $result = $this->toList($deliveryList, $params->getPage(), $params->getPageSize());
        collect($result['list'])->each(function ($item) {
            $item->actions = ['view', 'express'];
        });
        return $result;
    }

    public function get(int $deliveryId)
    {
        return DeliveryRepository::getInstance()->getDeliveryInfo($deliveryId);
    }
}
